/*
 * Copyright (c) 2010-2013 Mark Allen.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.faceboob.api.restfb.example;

import static java.lang.String.format;
import static java.lang.System.out;
import static java.util.Collections.singletonList;

import java.util.List;

import com.restfb.DefaultLegacyFacebookClient;
import com.restfb.Facebook;
import com.restfb.LegacyFacebookClient;
import com.restfb.Parameter;

/**
 * Examples of RestFB's Legacy REST API functionality.
 * 
 * @author <a href="http://restfb.com">Mark Allen</a>
 */
public class LegacyExample extends Example {
	/**
	 * RestFB Legacy REST API client.
	 */
	private final LegacyFacebookClient facebookClient;

	/**
	 * Entry point. You must provide a single argument on the command line: a valid OAuth access token.
	 * 
	 * @param args
	 *            Command-line arguments.
	 * @throws IllegalArgumentException
	 *             If no command-line arguments are provided.
	 */
	public static void main(final String[] args) {

		new LegacyExample(
				"BAAHXKxGP43MBABI7JCP7DGjjsz20S3IAZCfNZA2jnYppVQFfjFh6pJQAgkwaq7Wqg3zMi4O7jsrMKAsZCCRISVZCIFULVSqOhezLe9Sx8uZCZBBluSaP3dsJ8zL1NYTdHzPlUYSejsSSAohHKfqRHElvRZB2FwvaLyjQpaYHFIWA6njgelkViRgvKeZCmaPaqZC49QsIuSZCIP9Vn2eX7KvkbhIDlsRNxX5jYZD")
				.runEverything();
	}

	LegacyExample(final String accessToken) {
		this.facebookClient = new DefaultLegacyFacebookClient(accessToken);
	}

	void runEverything() {
		this.object();
		this.list();
		this.fql();
		this.publish();
	}

	void object() {
		final Long uid = this.facebookClient.execute("users.getLoggedInUser", Long.class);
		System.out.println("My UID is " + uid);
	}

	void list() {
		out.println("* Call that returns a list *");

		final List<LegacyUser> users = this.facebookClient.executeForList("Users.getInfo", LegacyUser.class,
				Parameter.with("uids", "220439, 7901103"), Parameter.with("fields", "last_name, first_name"));

		out.println("Users: " + users);
	}

	/**
	 * Holds user information as retrieved in {@link #list()}.
	 */
	public static class LegacyUser {
		@Facebook("first_name")
		String firstName;

		@Facebook("last_name")
		String lastName;

		/**
		 * @see java.lang.Object#toString()
		 */
		@Override
		public String toString() {
			return format("%s %s", this.firstName, this.lastName);
		}
	}

	void fql() {
		final Long uid = this.facebookClient.execute("users.getLoggedInUser", Long.class);

		// FQL query which asks Facebook for your friends' names, profile
		// picture
		// URLs, and network affiliations
		final String query = "SELECT name, pic_big, affiliations FROM user " + "WHERE uid IN (SELECT uid2 FROM friend WHERE uid1=" + uid
				+ ")";

		// Executes an API call with result mapped to a list of classes we've
		// defined. Note that you can pass in an arbitrary number of Parameters
		// -
		// here we send along the query as well as the "give me HTTPS URLs" flag
		final List<LegacyFqlUser> users = this.facebookClient.executeForList("fql.query", LegacyFqlUser.class,
				Parameter.with("query", query), Parameter.with("return_ssl_resources", "true"));

		System.out.println("My friends and their affiliations:");

		for (final LegacyFqlUser user : users) {
			System.out.println(user);
		}
	}

	/**
	 * Holds user information as retrieved in {@link #list()}.
	 */
	public static class LegacyFqlUser {
		// By default, assumes JSON attribute name is the same as the Java field
		// name
		@Facebook
		String name;

		// If your Java field name is different than the JSON attribute name,
		// just
		// specify the JSON attribute name
		@Facebook("pic_big")
		String pictureUrl;

		@Facebook
		List<Affiliation> affiliations;

		@Override
		public String toString() {
			return format("Name: %s\nProfile Image URL: %s\nAffiliations: %s", this.name, this.pictureUrl, this.affiliations);
		}
	}

	public static class Affiliation {
		@Facebook
		String name;

		@Facebook
		String type;

		@Override
		public String toString() {
			return format("%s (%s)", this.name, this.type);
		}
	}

	void publish() {
		out.println("* Publishes to your feed *");

		final ActionLink category = new ActionLink();
		category.href = "http://bit.ly/KYbaN";
		category.text = "humor";

		final Properties properties = new Properties();
		properties.category = category;
		properties.ratings = "5 stars";

		final Medium medium = new Medium();
		medium.href = "http://bit.ly/187gO1";
		medium.src = "http://bit.ly/GaTlC";
		medium.type = "image";

		final Attachment attachment = new Attachment();
		attachment.name = "i'm bursting with joy";
		attachment.href = "http://bit.ly/187gO1";
		attachment.caption = "{*actor*} rated the lolcat 5 stars";
		attachment.description = "a funny looking cat";
		attachment.properties = properties;
		attachment.media = singletonList(medium);

		// Send the request to Facebook.
		// We specify the fact that we're expecting a String response and that
		// we're
		// passing along an attachment (defined above).

		final String postId = this.facebookClient.execute("stream.publish", String.class, Parameter.with("attachment", attachment));

		out.println("ID of the post you just published: " + postId);
	}

	// Below are classes that get converted to JSON and passed along to the
	// stream.publish call.

	public static class ActionLink {
		@Facebook
		String text;

		@Facebook
		String href;
	}

	public static class Medium {
		@Facebook
		String type;

		@Facebook
		String src;

		@Facebook
		String href;
	}

	public static class Properties {
		@Facebook
		ActionLink category;

		@Facebook
		String ratings;
	}

	public static class Attachment {
		@Facebook
		String name;

		@Facebook
		String href;

		@Facebook
		String caption;

		@Facebook
		String description;

		@Facebook
		Properties properties;

		@Facebook
		List<Medium> media;
	}
}